package com.admin.oauth.util;

import com.admin.common.constant.ExceptionConstant;
import com.admin.common.enums.DataScopeEnum;
import com.admin.common.exception.BadRequestException;
import com.admin.core.entity.SysRole;
import com.admin.core.entity.SysUser;
import org.apache.commons.lang3.StringUtils;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 数据范围
 * 表需要字段：create_by、dept_id
 *
 * 使用：
 * --dto添加 dataScopeSql 字段
 * --dto.setDataScopeSql(dataScopeService.dataScope()); // 代码中调用
 * --and ${entity.dataScopeSql} // 在 sql 中 添加，如果是关联查询，请使用子查询
 *
 * todo
 *  方法添加注解方式 DataScope，通过aop处理：
 *      mp查询模式：没法弄，
 *  添加特定字段|继承特定类：判断是否有该字段，将 数据权限 添加到 sql。
 *      mp查询模式：RowBounds rowBounds = (RowBounds) args[2];  的 param1 可以拿到字段值，拿不到对象@TableField(exist = false)的属性
 *  字段添加注解 标识部门 DataScopeFieldDept 和创建人 DataScopeFieldCreateBy的注解，
 *      如果有标记，判断是否有 @TableField，有获取其value值，没有 @TableField 则用属性名转下划线
 *      如果没有标记默认使用 dept_id、create_by
 *
 * @author sq-lan
 */
public class DataScopeUtil {

    public static String dataScope() {
        return dataScope("dept_id");
    }

    public static String dataScope(String field) {
        SysUser user = LoginUserUtil.user();
        if (user.getIsAdmin()) {
            return null;
        }
        List<SysRole> roles = user.getRoles();
        Set<Integer> dataScopeSet = roles.stream().map(SysRole::getDataScope).collect(Collectors.toSet());
        // 如果有一个数据权限为 全部，则为可看全部
        if (dataScopeSet.contains(DataScopeEnum.ALL.getValue())) {
            return null;
        }
        // 只有 本人 的
        if (dataScopeSet.size() == 1 && dataScopeSet.contains(DataScopeEnum.SELF.getValue())) {
            return "create_by = '" + user.getUsername() + "'";
        }
        // 有 本级 | 本级及以下 | 自定义,将其所有部门加起来
        Set<Integer> scopes = LoginUserUtil.dataScopes();
        String sql = field + " in (" + StringUtils.join(scopes, ",") + ")";
        // 有本人的，拼接创建人为 本人的sql
        if (dataScopeSet.contains(DataScopeEnum.SELF.getValue())) {
            sql = "(" + sql + " or " + "create_by = '" + user.getUsername() + "')";
        }
        return sql;
    }

    public static String dataScopeForDept() {
        return dataScope("id");
    }

    /**
     * 越权
     */
    public static void overstep(int deptId, int createBy) {
        SysUser user = LoginUserUtil.user();
        if (user.getIsAdmin()) {
            return;
        }
        List<SysRole> roles = user.getRoles();
        Set<Integer> dataScopeSet = roles.stream().map(SysRole::getDataScope).collect(Collectors.toSet());
        // 如果有一个数据权限为 全部，则为可看全部
        if (dataScopeSet.contains(DataScopeEnum.ALL.getValue())) {
            return;
        }
        // 只有 本人 的，检查创建人是不是本人
        if (dataScopeSet.size() == 1 && dataScopeSet.contains(DataScopeEnum.SELF.getValue())) {
            if(createBy != user.getId()) {
                throw new BadRequestException(ExceptionConstant.PERMISSION_DENIED2);
            }
        }
        // 有 本级 | 本级及以下 | 自定义,检查该数据的部门是否在数据范围内
        Set<Integer> scopes = LoginUserUtil.dataScopes();
        if(!scopes.contains(deptId)) {
            throw new BadRequestException(ExceptionConstant.PERMISSION_DENIED2);
        }
    }

    /**
     * 显示
     *  key：值，value：显示文字
     * @return {@link Map}<{@link Integer}, {@link String}>
     */
    public static Map<Integer, String> show() {
        Map<Integer, String> map = new LinkedHashMap<>();
        SysUser user = LoginUserUtil.user();
        // 如果有一个数据权限为 全部 || 是管理员，显示所有
        if (user.getIsAdmin()) {
            DataScopeEnum[] values = DataScopeEnum.values();
            for (DataScopeEnum anEnum : values) {
                map.put(anEnum.getValue(), anEnum.getLabel());
            }
            return map;
        }

        List<SysRole> roles = user.getRoles();
        Set<Integer> dataScopeSet = roles.stream().map(SysRole::getDataScope).collect(Collectors.toSet());

        if (dataScopeSet.contains(DataScopeEnum.ALL.getValue())) {
            DataScopeEnum[] values = DataScopeEnum.values();
            for (DataScopeEnum anEnum : values) {
                map.put(anEnum.getValue(), anEnum.getLabel());
            }
            return map;
        }

        // 本级及以下：除 全部、自定义
        if (dataScopeSet.contains(DataScopeEnum.DEPT_AND_CHILD.getValue())) {
            DataScopeEnum[] values = DataScopeEnum.values();
            for (DataScopeEnum anEnum : values) {
                if(!DataScopeEnum.ALL.getValue().equals(anEnum.getValue()) && !DataScopeEnum.CUSTOMIZE.getValue().equals(anEnum.getValue())) {
                    map.put(anEnum.getValue(), anEnum.getLabel());
                }
            }
        }

        if (dataScopeSet.contains(DataScopeEnum.DEPT.getValue())) {
            map.put(DataScopeEnum.DEPT.getValue(), DataScopeEnum.DEPT.getLabel());
        }

        if (dataScopeSet.contains(DataScopeEnum.CUSTOMIZE.getValue())) {
            map.put(DataScopeEnum.CUSTOMIZE.getValue(), DataScopeEnum.CUSTOMIZE.getLabel());
        }

        map.put(DataScopeEnum.SELF.getValue(), DataScopeEnum.SELF.getLabel());
        return map;
    }
}
